import { useMemo, useEffect, useState, useCallback, useRef } from "react";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogTitle from "@mui/material/DialogTitle";
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import ToggleButtonGroup from "@mui/material/ToggleButtonGroup";
import ToggleButton from "@mui/material/ToggleButton";
import DataPaper from "./DataPaper";
import ButtonGroup from "@mui/material/ButtonGroup";
import Alert from "@mui/material/Alert";
import Collapse from "@mui/material/Collapse";
import Stack from "@mui/material/Stack";
import { useThrottle } from "@react-hook/throttle";
import cookieApis from "../apis/cookies.mjs";
import { GM_registerMenuCommand } from "tm";
import { tsToString, defaultTime } from "../utilities.mjs";
import { titleFont, firstDlg, secondDlg, buttonFont } from "../data.mts";

export default function CookieDialog(properties: { inner?: HTMLElement }) {
  const [open, setOpen] = useState(false);
  const [openEd, setOpenEd] = useState(false);
  const [data, setData] = useState<
    Awaited<ReturnType<typeof cookieApis.query>>["data"]
  >([]);
  const [content, setContent] = useThrottle<(typeof data)[number]>({});
  const [edAdd, setEdAdd] = useState<boolean>(false);
  const timeReference = useRef<HTMLInputElement>(null);
  const [expire, setExpire] = useState<"custom" | "session">("custom");
  const [alertOpen, setAlertOpen] = useState(false);
  const timeString = useMemo(
    () =>
      typeof content.expires == "number"
        ? tsToString(content.expires)
        : tsToString(defaultTime()),
    [content.expires],
  );

  useEffect(() => {
    GM_registerMenuCommand("Cookie UI", () => {
      setOpen(true);
      updateData();
    });
  }, []);

  const updateInput = useCallback(
    (time: number | null | undefined) => {
      const tinput = timeReference.current;
      if (tinput) {
        tinput.valueAsNumber = time ?? defaultTime();
      }
    },
    [timeReference],
  );

  const handleCloseEd = () => {
    setContent({});
    setOpenEd(false);
    setExpire("custom");
  };

  const handleTimeChange = useCallback(() => {
    const tinput = timeReference.current;
    if (tinput) {
      const current = { ...content };
      const time = tinput.valueAsNumber;
      current.expires = Number.isNaN(time) ? defaultTime() : time;
      setContent(current);
    }
  }, [timeReference, content, setContent]);

  const updateData = () => {
    cookieApis
      .query()
      .then((result) => {
        setData(result.data);
      })
      .catch(() => {
        setOpen(false);
      });
  };

  return (
    <>
      <input
        type="datetime-local"
        ref={timeReference}
        onChange={handleTimeChange}
        style={{
          display: "none",
        }}
      />
      <Dialog
        open={open}
        onClose={() => {
          setOpen(false);
        }}
        sx={firstDlg}
        container={properties.inner}
      >
        <DialogTitle sx={titleFont}>
          <Stack
            direction="row"
            justifyContent="space-between"
            alignItems="center"
            spacing={10}
          >
            Cookie
            <Button
              onClick={() => {
                const current = alertOpen;
                setAlertOpen(!current);
              }}
              size="small"
              sx={{
                fontSize: 12,
              }}
            >
              {alertOpen ? "关闭说明" : "查看说明"}
            </Button>
          </Stack>
        </DialogTitle>
        <DialogContent
          sx={{
            display: "flex",
            flexDirection: "column",
          }}
        >
          <Collapse
            in={alertOpen}
            sx={{
              flexShrink: 0,
            }}
          >
            <Alert
              severity="warning"
              sx={{
                fontSize: 12,
                fontWeight: 800,
                mb: "5px",
              }}
              onClick={() => {
                setAlertOpen(false);
              }}
            >
              依赖于 CookieStore API，所以只有在 87+ 内核以及 https
              协议的网站才能使用此功能。
              <br />
              <br />
              依赖于 HTMLInputElement.showPicker，修改过期时间需要 99+ 内核。
              <br />
              <br />
              无法得到第三方 Cookie 和带有 HttpOnly 属性的 Cookie 。<br />
              <br />
              在这里添加或修改的 Cookie 会被加上 secure 属性（HTTPS），http
              协议的网站将无法得到这些 Cookie 。<br />
              <br />
              只能删除与页面域名完全匹配的 Cookie 。<br />
              <br />
              如果设置的过期时间早于当前时间，则 Cookie 会立即过期并被删除。
            </Alert>
          </Collapse>
          <List
            sx={{
              width: "100%",
              maxWidth: 360,
              position: "relative",
              overflow: "auto",
              maxHeight: "62vh",
            }}
          >
            {data.map((cookie, index, cookies) => (
              <ListItem key={cookie.name}>
                <DataPaper
                  dKey={cookie.name!}
                  dValue={cookie.value}
                  openEdit={() => {
                    setContent(cookie);
                    setEdAdd(false);
                    setOpenEd(true);
                    updateInput(cookie.expires);
                  }}
                  remove={() => {
                    cookieApis
                      .remove(cookie.name!)
                      .then(() => {
                        updateData();
                      })
                      .catch((error: unknown) => {
                        console.error(error);
                        updateData();
                      });
                  }}
                  text={`${String(index + 1)}/${String(cookies.length)}
${cookieApis.stringify(cookie, false)}`}
                />
              </ListItem>
            ))}
          </List>
          <ButtonGroup fullWidth sx={{ mt: "5px" }}>
            <Button
              onClick={() => {
                setContent({
                  sameSite: "lax",
                });
                updateInput(defaultTime());
                setEdAdd(true);
                setOpenEd(true);
              }}
              color="success"
              sx={buttonFont}
              variant="outlined"
            >
              添加
            </Button>
            {data.length > 0 ? (
              <Button
                color="error"
                sx={buttonFont}
                variant="outlined"
                onClick={() => {
                  cookieApis
                    .clear()
                    .then(() => {
                      updateData();
                    })
                    .catch((error: unknown) => {
                      console.error(error);
                      updateData();
                    });
                }}
              >
                清空
              </Button>
            ) : (
              void 0
            )}
          </ButtonGroup>
        </DialogContent>
      </Dialog>
      <Dialog
        open={openEd}
        onClose={handleCloseEd}
        container={properties.inner}
        sx={secondDlg}
      >
        <DialogTitle sx={titleFont}>{edAdd ? "添加" : "编辑"}</DialogTitle>
        <DialogContent
          sx={{
            display: "flex",
            flexDirection: "column",
          }}
        >
          <TextField
            margin="dense"
            label="键"
            value={content.name}
            InputLabelProps={{ shrink: true }}
            variant="standard"
            fullWidth
            required
            disabled={!edAdd}
            onChange={(v) => {
              const current = { ...content };
              current.name = v.target.value;
              setContent(current);
            }}
          />
          <TextField
            margin="dense"
            multiline
            rows={4}
            label="值"
            type="text"
            fullWidth
            InputLabelProps={{ shrink: content.value !== "" }}
            variant="standard"
            value={content.value}
            onChange={(v) => {
              const current = { ...content };
              current.value = v.target.value;
              setContent(current);
            }}
          />
          <TextField
            margin="dense"
            label="作用域名"
            InputLabelProps={{ shrink: true }}
            value={content.domain ?? location.hostname}
            variant="standard"
            fullWidth
            onChange={(v) => {
              const current = { ...content };
              current.domain = v.target.value;
              setContent(current);
            }}
          />
          <TextField
            margin="dense"
            label="作用路径"
            InputLabelProps={{ shrink: true }}
            value={content.path ?? "/"}
            variant="standard"
            fullWidth
            onChange={(v) => {
              const current = { ...content };
              current.path = v.target.value;
              setContent(current);
            }}
          />
          <ToggleButtonGroup
            color="primary"
            value={content.sameSite ?? "lax"}
            exclusive
            fullWidth
            onChange={(_event, v) => {
              const current = { ...content };
              if (v !== null) {
                current.sameSite = v as typeof content.sameSite;
              }
              setContent(current);
            }}
            sx={{
              my: "2px",
              mx: 0,
            }}
          >
            <ToggleButton
              value="strict"
              sx={{
                fontSize: 15,
              }}
            >
              Strict
            </ToggleButton>
            <ToggleButton
              value="lax"
              sx={{
                fontSize: 15,
              }}
            >
              Lax
            </ToggleButton>
            <ToggleButton
              value="none"
              sx={{
                fontSize: 15,
              }}
            >
              None
            </ToggleButton>
          </ToggleButtonGroup>
          <ToggleButtonGroup
            color="primary"
            value={expire}
            orientation="vertical"
            exclusive
            fullWidth
            onChange={(_event, v) => {
              if (v !== null) {
                setExpire(v as "custom" | "session");
              }
            }}
            sx={{
              my: "2px",
              mx: 0,
            }}
          >
            <ToggleButton
              value="session"
              sx={{
                fontSize: 15,
              }}
            >
              会话结束
            </ToggleButton>
            <ToggleButton
              sx={{
                fontSize: 15,
              }}
              value="custom"
              onClick={() => {
                const tinput = timeReference.current;
                if (tinput) {
                  tinput.showPicker();
                }
              }}
            >
              {timeString}
            </ToggleButton>
          </ToggleButtonGroup>
        </DialogContent>
        <DialogActions>
          <Button onClick={handleCloseEd} sx={buttonFont}>
            取消
          </Button>
          <Button
            sx={buttonFont}
            onClick={() => {
              if (content.name !== "") {
                const current = { ...content };
                delete current.secure;
                if (expire === "session") {
                  current.expires = undefined;
                }
                cookieApis
                  .change(current as Parameters<typeof cookieApis.change>[0])
                  .then(() => {
                    updateData();
                    setOpenEd(false);
                    setExpire("custom");
                  })
                  .catch((error: unknown) => {
                    console.error(error);
                    updateData();
                    setOpenEd(false);
                    setExpire("custom");
                  });
              }
            }}
            variant="contained"
          >
            保存
          </Button>
        </DialogActions>
      </Dialog>
    </>
  );
}
